//@author A0081058H
package net.mysoc.w111j.ui.generatereport;

import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Rectangle2D;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.stage.Modality;
import javafx.stage.Screen;
import javafx.stage.Stage;
import net.mysoc.w111j.model.Money;
import net.mysoc.w111j.service.ExpenseService;
import net.mysoc.w111j.service.Report;
import net.mysoc.w111j.service.ReportService;
import net.mysoc.w111j.service.ReportType;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * The presenter for reports.
 */
public class GenerateReportPresenter {
    private static Logger logger = LoggerFactory.getLogger(GenerateReportPresenter.class);

    private final GenerateReportModel model;
    private final GenerateReportView view;
    private final ExpenseService expenseService;
    private Stage dialogStage;

    /**
     * Constructor. Links the {@code GenerateReportModel}, {@code GenerateReportView} to this
     * {@code GenerateReportPresenter}. Also stores a reference to the {@code ExpenseService}.
     *
     * @param model the {@code GenerateReportModel} to link to this {@code GenerateReportPresenter}.
     * @param view the {@code GenerateReportView} to link to this {@code GenerateReportPresenter}.
     * @param expenseService the {@code ExpenseService} to retrieve expense data from.
     */
    public GenerateReportPresenter(GenerateReportModel model, final GenerateReportView view,
            ExpenseService expenseService) {
        this.model = model;
        this.view = view;
        this.view.setPresenter(this);
        this.expenseService = expenseService;
        this.view.buildCharts();

        // Refresh selected tab when date is changed
        this.model.startDateProperty().addListener(new ChangeListener<Object>() {
            @Override
            public void changed(ObservableValue<?> o, Object oldVal, Object newVal) {
                try {
                    view.refreshSelectedTab();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Returns the {@code GenerateReportView} linked to this {@code GenerateReportPresenter}.
     *
     * @return the {@code GenerateReportView} linked to this {@code GenerateReportPresenter}.
     */
    public GenerateReportView getView() {
        return this.view;
    }

    /**
     * Creates, if it does not exist, the dialog window and shows it.
     *
     * @param parentStage the parent {@code Stage} for this window.
     */
    public void showDialog(Stage parentStage) {
        if (this.dialogStage == null) {
            this.dialogStage = new Stage();
            this.dialogStage.initModality(Modality.WINDOW_MODAL);
            this.dialogStage.setMinWidth(800);
            this.dialogStage.setMinHeight(600);
            Screen screen = Screen.getPrimary();
            Rectangle2D bounds = screen.getVisualBounds();
            this.dialogStage.setWidth(bounds.getWidth() / 1.3);
            this.dialogStage.setHeight(bounds.getHeight() / 1.3);
            this.dialogStage.initOwner(parentStage);
            this.dialogStage.setTitle("EzXpns - Reports");
            this.dialogStage.getIcons().add(new Image("ezicon.png"));
            Scene scene = new Scene(getView());
            scene.getStylesheets().add("ezxpns.css");
            this.dialogStage.setScene(scene);
        }

        refresh();
        dialogStage.show();
    }

    /**
     * Refreshes the view by rebuilding the charts. Charts, while rebuilding, will (re)request the latest information.
     */
    public void refresh() {
        this.view.buildCharts();
        this.view.refreshSelectedTab();
    }

    /**
     * Handles the OK button in the view.
     */
    public void handleOK() {
        // No action is taken, the reports window is just being closed.
        logger.debug("OK!");
    }

    /**
     * Gets the expense data from the {@code ExpenseService} for chart generation. {@code ExpenseService} readies
     * (formats) the data for chart generation.
     *
     * @param reportType
     * @return data from the {@code ExpenseService}.
     */
    public Report handleGetData(ReportType reportType) {
        return this.expenseService.generateReport(reportType, this.model.getStartDate());
    }

    /**
     * Gets the expenditure data from the {@code ExpenseService} for statistics.
     *
     * @param reportType
     * @return data from the {@code ExpenseService}.
     */
    public Money handleGetExpenditure(ReportType reportType) {
        return this.expenseService.getCurrentMonthExpenditure();
    }

    /**
     * Offsets the start date, affected by type. For instance, off-setting a MONTHLY report by -1 will push the start
     * date back a month.
     *
     * @param offset the amount to offset, affected by type
     * @param type how many days to multiply the offset
     */
    public void handleOffset(int offset, ReportType type) {
        this.model.setStartDate(ReportService.getDateOffsetByPeriod(model.getStartDate(), type, offset));
    }
}
